package com.ssy.lingxi.member.merchant.serviceimpl.web;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.member.MemberTypeEnum;
import com.ssy.lingxi.common.constant.member.RoleTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.CollectionPageUtil;
import com.ssy.lingxi.member.merchant.api.model.constant.MemberProcessTypeEnum;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.ProcessBO;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.NamePageVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.RoleIdPageVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.BaseMemberProcessVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.MemberConfigGroupVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.MemberConfigNameVO;
import com.ssy.lingxi.member.merchant.model.vo.basic.response.RoleManageVO;
import com.ssy.lingxi.member.merchant.model.vo.platform.response.RoleRuleManageVO;
import com.ssy.lingxi.member.merchant.model.vo.validate.request.*;
import com.ssy.lingxi.member.merchant.model.vo.validate.response.MemberProcessQueryVO;
import com.ssy.lingxi.member.merchant.model.vo.validate.response.MemberProcessVO;
import com.ssy.lingxi.member.merchant.repository.BaseMemberProcessRepository;
import com.ssy.lingxi.member.merchant.repository.MemberConfigRepository;
import com.ssy.lingxi.member.merchant.repository.MemberProcessRuleRepository;
import com.ssy.lingxi.member.merchant.repository.RoleRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberRegisterDetailService;
import com.ssy.lingxi.member.merchant.service.base.IBaseSiteService;
import com.ssy.lingxi.member.merchant.service.web.IMemberProcessRuleService;
import com.ssy.lingxi.member.merchant.service.web.IPlatformMemberRoleRuleService;
import com.ssy.lingxi.member.merchant.utils.NumberUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 会员管理流程规则配置相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-05-15
 */
@Service
public class MemberProcessRuleServiceImpl implements IMemberProcessRuleService {

    @Resource
    private IBaseMemberCacheService memberCacheService;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private BaseMemberProcessRepository baseMemberProcessRepository;

    @Resource
    private MemberProcessRuleRepository memberProcessRuleRepository;

    @Resource
    private MemberConfigRepository memberConfigRepository;

    @Resource
    private IBaseMemberRegisterDetailService baseMemberRegisterDetailService;

    @Resource
    private IBaseSiteService siteService;

    @Resource
    private IPlatformMemberRoleRuleService roleRuleService;

    /**
     * 分页查询会员流程规则配置列表
     *
     * @param headers Http头部信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<MemberProcessQueryVO>> pageMemberProcessRules(HttpHeaders headers, NamePageVO pageVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);
        Pageable pageable = PageRequest.of(pageVO.getCurrent() -1, pageVO.getPageSize(), Sort.by("id").descending());
        Specification<MemberProcessRuleDO> specification = (Specification<MemberProcessRuleDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), loginUser.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("roleId").as(Long.class), loginUser.getMemberRoleId()));
            if(StringUtils.hasLength(pageVO.getName())) {
                list.add(criteriaBuilder.like(root.get("ruleName").as(String.class), "%" + pageVO.getName().trim() + "%"));
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Page<MemberProcessRuleDO> pageList = memberProcessRuleRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(memberProcessRuleDO -> {
            MemberProcessQueryVO queryVO = new MemberProcessQueryVO();
            queryVO.setId(memberProcessRuleDO.getId());
            queryVO.setCreateTime(memberProcessRuleDO.getCreateTime() == null ? "" : memberProcessRuleDO.getCreateTime().format(ServiceConfig.DEFAULT_DATETIME_FORMATTER));
            queryVO.setRuleName(memberProcessRuleDO.getRuleName());
            queryVO.setRoleName(memberProcessRuleDO.getSubRole().getRoleName());
            queryVO.setRoleTypeName(RoleTypeEnum.getName(memberProcessRuleDO.getSubRole().getRoleType().getTypeEnum()));
            queryVO.setMemberTypeName(MemberTypeEnum.getCodeMessage(memberProcessRuleDO.getSubRole().getMemberType().getTypeEnum()));
            queryVO.setBusinessTypeName(memberProcessRuleDO.getSubRole().getBusinessType().getBusinessTypeName());
            queryVO.setStatus(memberProcessRuleDO.getStatus());
            return queryVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 查询入库流程、变更流程列表
     *
     * @param headers Http头部信息
     * @return 查询结果
     */
    @Override
    public Wrapper<List<BaseMemberProcessVO>> listBaseMemberProcesses(HttpHeaders headers) {
        memberCacheService.needLoginFromBusinessPlatform(headers);
        return Wrapper.success(baseMemberProcessRepository.findAll().stream().map(baseMemberProcessDO -> {
            BaseMemberProcessVO processVO = new BaseMemberProcessVO();
            processVO.setId(baseMemberProcessDO.getId());
            processVO.setProcessName(baseMemberProcessDO.getProcessName());
            processVO.setProcessType(baseMemberProcessDO.getProcessType());
            processVO.setProcessTypeName(MemberProcessTypeEnum.getMsg(baseMemberProcessDO.getProcessType()));
            processVO.setDescription(baseMemberProcessDO.getDescription());
            return processVO;
        }).collect(Collectors.toList()));
    }

    /**
     * 查询角色列表
     *
     * @param headers Http头部信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<RoleManageVO>> pageRoles(HttpHeaders headers, NamePageVO pageVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);
        Wrapper<Boolean> wrapper = siteService.isEnableMultiTenancy(headers);
        if (!wrapper.getData()) {//如果没有开启saas多租户部署
            return pageRoles(loginUser, pageVO);
        } else {//如果开启saas多租户部署
            //按照指定会员id取当前会员配置的适用类型
            List<RoleRuleManageVO> manageVOList = roleRuleService.subMemberRoles(loginUser.getMemberId()).getData();
            if (manageVOList == null) {
                throw new BusinessException(ResponseCode.MC_MS_SUB_MEMBER_NO_SUITABLE_ROLE);
            }
            // TODO: 后期要改成qdsl
            //因为数据量很少，所以在内存做筛选
            //计算分页参数
            int size = manageVOList.size();
            int fromIndex = (pageVO.getCurrent() - 1) * pageVO.getPageSize();
            if (fromIndex > size) {
                return Wrapper.success(new PageData<>((long) size, new ArrayList<>()));
            }
            int toIndex = pageVO.getCurrent() * pageVO.getPageSize();
            if (toIndex > size) {
                toIndex = size;
            }

            manageVOList = manageVOList.stream()
                    .filter(roleRuleManageVO -> {
                        if (StringUtils.hasLength(pageVO.getName())) {
                            return roleRuleManageVO.getRoleName().equals(pageVO.getName());
                        }
                        return true;
                    })
                    .sorted(Comparator.comparing(RoleRuleManageVO::getRoleId))
                    .collect(Collectors.toList())
                    .subList(fromIndex, toIndex);

            List<RoleManageVO> roleManageVOList = manageVOList.stream().map(roleRuleManageVO -> {
                RoleManageVO roleManageVO = new RoleManageVO();
                roleManageVO.setRoleId(roleRuleManageVO.getRoleId());
                roleManageVO.setRoleName(roleRuleManageVO.getRoleName());
                roleManageVO.setRoleTypeName(roleRuleManageVO.getRoleTypeName());
                roleManageVO.setMemberTypeName(roleRuleManageVO.getMemberTypeName());
                roleManageVO.setBusinessTypeName(roleRuleManageVO.getBusinessTypeName());
                roleManageVO.setStatus(EnableDisableStatus.ENABLE.getCode());
                return roleManageVO;
            }).collect(Collectors.toList());
            return Wrapper.success(new PageData<>((long) size, roleManageVOList));
        }
    }

    /**
     * 查询角色列表
     * @param loginUser 登录会员信息
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<RoleManageVO>> pageRoles(UserLoginCacheDTO loginUser, NamePageVO pageVO) {
        //规则：
        // 1). 上级会员角色为企业会员，下级会员角色为企业会员：无限制
        // 2). 上级会员角色为企业会员，下级会员角色为渠道会员：不允许创建
        // 3). 上级会员角色为渠道会员，下级会员角色为企业会员：不允许创建
        // 4). 上级会员角色为渠道会员，下级会员角色为渠道会员：判断下级会员是否有另一个服务消费者角色在关系树中

        Pageable pageable = PageRequest.of(pageVO.getCurrent() -1, pageVO.getPageSize(), Sort.by("id").ascending());
        Specification<RoleDO> specification;
        if(loginUser.getMemberType().equals(MemberTypeEnum.MERCHANT.getCode()) || loginUser.getMemberType().equals(MemberTypeEnum.MERCHANT_PERSONAL.getCode())) {
            specification = (Specification<RoleDO>) (root, query, criteriaBuilder) -> {
                List<Predicate> list = new ArrayList<>();
                list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), EnableDisableStatus.ENABLE.getCode()));
                list.add(criteriaBuilder.notEqual(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
                if(StringUtils.hasLength(pageVO.getName())) {
                    list.add(criteriaBuilder.like(root.get("roleName").as(String.class), "%" + pageVO.getName().trim() + "%"));
                }
                Join<RoleDO, MemberTypeDO> memberTypeJoin = root.join("memberType", JoinType.LEFT);
                list.add(criteriaBuilder.or(criteriaBuilder.equal(memberTypeJoin.get("typeEnum").as(Integer.class), MemberTypeEnum.MERCHANT.getCode()), criteriaBuilder.equal(memberTypeJoin.get("typeEnum").as(Integer.class), MemberTypeEnum.MERCHANT_PERSONAL.getCode())));
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            };
        } else if(loginUser.getMemberType().equals(MemberTypeEnum.CHANNEL.getCode()) || loginUser.getMemberType().equals(MemberTypeEnum.CHANNEL_PERSONAL.getCode())) {
            specification = (Specification<RoleDO>) (root, query, criteriaBuilder) -> {
                List<Predicate> list = new ArrayList<>();
                list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), EnableDisableStatus.ENABLE.getCode()));
                list.add(criteriaBuilder.notEqual(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
                if(StringUtils.hasLength(pageVO.getName())) {
                    list.add(criteriaBuilder.like(root.get("roleName").as(String.class), "%" + pageVO.getName().trim() + "%"));
                }
                Join<RoleDO, MemberTypeDO> memberTypeJoin = root.join("memberType", JoinType.LEFT);
                list.add(criteriaBuilder.or(criteriaBuilder.equal(memberTypeJoin.get("typeEnum").as(Integer.class), MemberTypeEnum.CHANNEL.getCode()), criteriaBuilder.equal(memberTypeJoin.get("typeEnum").as(Integer.class), MemberTypeEnum.CHANNEL_PERSONAL.getCode())));
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            };
        } else {
            specification = (Specification<RoleDO>) (root, query, criteriaBuilder) -> {
                List<Predicate> list = new ArrayList<>();
                list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), EnableDisableStatus.ENABLE.getCode()));
                list.add(criteriaBuilder.notEqual(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
                if(StringUtils.hasLength(pageVO.getName())) {
                    list.add(criteriaBuilder.like(root.get("roleName").as(String.class), "%" + pageVO.getName().trim() + "%"));
                }
                Predicate[] p = new Predicate[list.size()];
                return criteriaBuilder.and(list.toArray(p));
            };
        }

        Page<RoleDO> pageList = roleRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(roleDO -> {
            RoleManageVO manageVO = new RoleManageVO();
            manageVO.setRoleId(roleDO.getId());
            manageVO.setRoleName(roleDO.getRoleName());
            manageVO.setRoleTypeName(RoleTypeEnum.getName(roleDO.getRoleType().getTypeEnum()));
            manageVO.setMemberTypeName(MemberTypeEnum.getCodeMessage(roleDO.getMemberType().getTypeEnum()));
            manageVO.setBusinessTypeName(roleDO.getBusinessType().getBusinessTypeName());
            manageVO.setStatus(roleDO.getStatus());
            return manageVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 查询平台默认注册资料
     *
     * @param headers Http头部信息
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<MemberConfigNameVO>> pageRoleConfigDetail(HttpHeaders headers, RoleIdPageVO pageVO) {
        memberCacheService.needLoginFromBusinessPlatform(headers);
        RoleDO roleDO = roleRepository.findById(pageVO.getRoleId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        Specification<MemberConfigDO> specification = (Specification<MemberConfigDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            Join<MemberConfigDO, RoleDO> roleJoin = root.join("roles", JoinType.LEFT);
            list.add(criteriaBuilder.equal(roleJoin.get("id").as(Long.class), pageVO.getRoleId()));
            if(StringUtils.hasLength(pageVO.getName())) {
                list.add(criteriaBuilder.like(root.get("fieldLocalName").as(String.class), "%" + pageVO.getName().trim() + "%"));
            }

            list.add(criteriaBuilder.equal(root.get("fieldStatus").as(Integer.class), EnableDisableStatus.ENABLE.getCode()));

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Pageable pageable = PageRequest.of(pageVO.getCurrent() -1, pageVO.getPageSize(), Sort.by("id").ascending());
        Page<MemberConfigDO> pageList = memberConfigRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(memberConfigDO -> {
            MemberConfigNameVO nameVO = new MemberConfigNameVO();
            nameVO.setId(memberConfigDO.getId());
            nameVO.setFieldLocalName(memberConfigDO.getFieldLocalName());
            nameVO.setGroupName(memberConfigDO.getGroupName());
            return nameVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 选择注册资料
     *
     * @param headers Http头部信息
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<MemberConfigNameVO>> pageConfigDetail(HttpHeaders headers, RoleIdPageVO pageVO) {
        memberCacheService.needLoginFromBusinessPlatform(headers);
        RoleDO roleDO = roleRepository.findById(pageVO.getRoleId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        //根据当前会员角色关联的注册资料进行排除
        List<Long> configIds = roleDO.getConfigs().stream().map(MemberConfigDO::getId).collect(Collectors.toList());
        Pageable pageable = PageRequest.of(pageVO.getCurrent() -1, pageVO.getPageSize(), Sort.by("id").ascending());
        Specification<MemberConfigDO> specification = (Specification<MemberConfigDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("fieldStatus").as(Integer.class), EnableDisableStatus.ENABLE.getCode()));
            //Not In查询
            if(!CollectionUtils.isEmpty(configIds)) {
                list.add(criteriaBuilder.not(root.get("id").as(Long.class).in(configIds)));
            }

            if(StringUtils.hasLength(pageVO.getName())) {
                list.add(criteriaBuilder.like(root.get("fieldLocalName").as(String.class), "%" + pageVO.getName().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Page<MemberConfigDO> pageList = memberConfigRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(memberConfigDO -> {
            MemberConfigNameVO nameVO = new MemberConfigNameVO();
            nameVO.setId(memberConfigDO.getId());
            nameVO.setFieldLocalName(memberConfigDO.getFieldLocalName());
            nameVO.setGroupName(memberConfigDO.getGroupName());
            return nameVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 预览注册资料
     *
     * @param headers   Http头部信息
     * @param previewVO 接口参数
     * @return 预览结果
     */
    @Override
    public Wrapper<List<MemberConfigGroupVO>> previewMemberDepositoryDetails(HttpHeaders headers, MemberProcessPreviewVO previewVO) {
        memberCacheService.needLoginFromBusinessPlatform(headers);
        RoleDO roleDO = roleRepository.findById(previewVO.getRoleId()).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        if(CollectionUtils.isEmpty(previewVO.getConfigIds())) {
            return Wrapper.success(new ArrayList<>());
        }

        List<MemberConfigDO> memberConfigs = memberConfigRepository.findByFieldStatusAndIdIn(EnableDisableStatus.ENABLE.getCode(), previewVO.getConfigIds());

        return Wrapper.success(baseMemberRegisterDetailService.groupMemberConfig(memberConfigs));
    }

    /**
     * 新增流程规则配置
     *
     * @param headers Http头部信息
     * @param addVO 接口参数
     * @return 新增结果
     */
    @Override
    public Wrapper<Void> addMemberProcessRule(HttpHeaders headers, MemberProcessAddVO addVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);
        if(NumberUtil.isNullOrZero(addVO.getDepositoryProcessId()) && NumberUtil.isNullOrZero(addVO.getChangedProcessId())) {
            return Wrapper.fail(ResponseCode.MC_MC_MEMBER_PROCESS_RULE_CAN_NOT_EMPLY);
        }

        RoleDO subRole = roleRepository.findById(addVO.getRoleId()).orElse(null);
        if(subRole == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        //判断角色流程是否已经存在
        if(memberProcessRuleRepository.existsByMemberIdAndRoleIdAndSubRole(loginUser.getMemberId(), loginUser.getMemberRoleId(), subRole)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_PROCESS_RULE_EXIST);
        }

        BaseMemberProcessDO baseDepositoryProcess = null;
        if(NumberUtil.notNullOrZero(addVO.getDepositoryProcessId())) {
            baseDepositoryProcess = baseMemberProcessRepository.findById(addVO.getDepositoryProcessId()).orElse(null);
            if(baseDepositoryProcess == null || !baseDepositoryProcess.getProcessType().equals(MemberProcessTypeEnum.MEMBER_DEPOSITORY.getCode())) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_PROCESS_RULE_NOT_EXIST);
            }
        }

        BaseMemberProcessDO baseDetailChangeProcess = null;
        if(NumberUtil.notNullOrZero(addVO.getChangedProcessId())) {
            baseDetailChangeProcess = baseMemberProcessRepository.findById(addVO.getChangedProcessId()).orElse(null);
            if(baseDetailChangeProcess == null || !baseDetailChangeProcess.getProcessType().equals(MemberProcessTypeEnum.MEMBER_MODIFICATION.getCode())) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DETAIL_CHANGE_PROCESS_RULE_NOT_EXIST);
            }
        }

        List<MemberConfigDO> memberConfigs = new ArrayList<>();
        if(!CollectionUtils.isEmpty(addVO.getConfigIds())) {
            memberConfigs = memberConfigRepository.findByFieldStatusAndIdIn(EnableDisableStatus.ENABLE.getCode(), addVO.getConfigIds());
            if(addVO.getConfigIds().size() != memberConfigs.size()) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_DETAIL_NOT_EXIST);
            }
        }

        MemberProcessRuleDO ruleDO = new MemberProcessRuleDO();
        ruleDO.setCreateTime(LocalDateTime.now());
        ruleDO.setMemberId(loginUser.getMemberId());
        ruleDO.setRoleId(loginUser.getMemberRoleId());
        ruleDO.setSubRole(subRole);
        ruleDO.setRuleName(addVO.getRuleName());
        ruleDO.setBaseDepositoryProcessId(baseDepositoryProcess == null ? 0L : baseDepositoryProcess.getId());
        ruleDO.setBaseDepositoryProcessKey(baseDepositoryProcess == null ? "" : baseDepositoryProcess.getProcessKey());
        ruleDO.setEmptyDepositoryProcess(baseDepositoryProcess == null ? null : baseDepositoryProcess.getEmptyProcess());
        ruleDO.setBaseDetailChangeProcessId(baseDetailChangeProcess == null ? 0L : baseDetailChangeProcess.getId());
        ruleDO.setBaseDetailChangeProcessKey(baseDetailChangeProcess == null ? "" : baseDetailChangeProcess.getProcessKey());
        ruleDO.setEmptyDetailChangeProcess(baseDetailChangeProcess == null ? null : baseDetailChangeProcess.getEmptyProcess());
        ruleDO.setStatus(EnableDisableStatus.ENABLE.getCode());
        ruleDO.setConfigs(new HashSet<>(memberConfigs));
        memberProcessRuleRepository.saveAndFlush(ruleDO);
        return Wrapper.success();
    }

    /**
     * 修改流程规则配置
     *
     * @param headers  Http头部信息
     * @param updateVO 接口参数
     * @return 修改结果
     */
    @Override
    public Wrapper<Void> updateMemberProcessRule(HttpHeaders headers, MemberProcessUpdateVO updateVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);
        if(NumberUtil.isNullOrZero(updateVO.getDepositoryProcessId()) && NumberUtil.isNullOrZero(updateVO.getChangedProcessId())) {
            return Wrapper.fail(ResponseCode.MC_MC_MEMBER_PROCESS_RULE_CAN_NOT_EMPLY);
        }

        MemberProcessRuleDO ruleDO = memberProcessRuleRepository.findById(updateVO.getId()).orElse(null);
        if(ruleDO == null || !ruleDO.getMemberId().equals(loginUser.getMemberId()) || !ruleDO.getRoleId().equals(loginUser.getMemberRoleId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_PROCESS_RULE_NOT_EXIST);
        }

        RoleDO subRole = roleRepository.findById(updateVO.getRoleId()).orElse(null);
        if(subRole == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        //判断角色流程是否已经存在
        if(memberProcessRuleRepository.existsByMemberIdAndRoleIdAndSubRoleAndIdNot(loginUser.getMemberId(), loginUser.getMemberRoleId(), subRole, updateVO.getId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_PROCESS_RULE_EXIST);
        }

        BaseMemberProcessDO baseDepositoryProcess = null;
        if(NumberUtil.notNullOrZero(updateVO.getDepositoryProcessId())) {
            baseDepositoryProcess = baseMemberProcessRepository.findById(updateVO.getDepositoryProcessId()).orElse(null);
            if(baseDepositoryProcess == null || !baseDepositoryProcess.getProcessType().equals(MemberProcessTypeEnum.MEMBER_DEPOSITORY.getCode())) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_PROCESS_RULE_NOT_EXIST);
            }
        }

        BaseMemberProcessDO baseDetailChangeProcess = null;
        if(NumberUtil.notNullOrZero(updateVO.getChangedProcessId())) {
            baseDetailChangeProcess = baseMemberProcessRepository.findById(updateVO.getChangedProcessId()).orElse(null);
            if(baseDetailChangeProcess == null || !baseDetailChangeProcess.getProcessType().equals(MemberProcessTypeEnum.MEMBER_MODIFICATION.getCode())) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DETAIL_CHANGE_PROCESS_RULE_NOT_EXIST);
            }
        }

        List<MemberConfigDO> memberConfigs = new ArrayList<>();
        if(!CollectionUtils.isEmpty(updateVO.getConfigIds())) {
            memberConfigs = memberConfigRepository.findByFieldStatusAndIdIn(EnableDisableStatus.ENABLE.getCode(), updateVO.getConfigIds());
            if (updateVO.getConfigIds().size() != memberConfigs.size()) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DEPOSITORY_DETAIL_NOT_EXIST);
            }
        }

        //删除之前的入库资料
        if(!CollectionUtils.isEmpty(ruleDO.getConfigs())) {
            ruleDO.getConfigs().clear();
        }

        ruleDO.setCreateTime(LocalDateTime.now());
        ruleDO.setSubRole(subRole);
        ruleDO.setRuleName(updateVO.getRuleName());
        ruleDO.setBaseDepositoryProcessId(baseDepositoryProcess == null ? 0L : baseDepositoryProcess.getId());
        ruleDO.setBaseDepositoryProcessKey(baseDepositoryProcess == null ? "" : baseDepositoryProcess.getProcessKey());
        ruleDO.setEmptyDepositoryProcess(baseDepositoryProcess == null ? null : baseDepositoryProcess.getEmptyProcess());
        ruleDO.setBaseDetailChangeProcessId(baseDetailChangeProcess == null ? 0L : baseDetailChangeProcess.getId());
        ruleDO.setBaseDetailChangeProcessKey(baseDetailChangeProcess == null ? "" : baseDetailChangeProcess.getProcessKey());
        ruleDO.setEmptyDetailChangeProcess(baseDetailChangeProcess == null ? null : baseDetailChangeProcess.getEmptyProcess());
        ruleDO.setStatus(EnableDisableStatus.ENABLE.getCode());
        ruleDO.getConfigs().clear();
        ruleDO.setConfigs(new HashSet<>(memberConfigs));
        memberProcessRuleRepository.saveAndFlush(ruleDO);
        return Wrapper.success();
    }

    /**
     * 查询流程规则配置详情
     *
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<MemberProcessVO> getMemberProcessRule(HttpHeaders headers, MemberProcessIdVO idVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);

        MemberProcessRuleDO ruleDO = memberProcessRuleRepository.findById(idVO.getId()).orElse(null);
        if(ruleDO == null || !ruleDO.getMemberId().equals(loginUser.getMemberId()) || !ruleDO.getRoleId().equals(loginUser.getMemberRoleId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_PROCESS_RULE_NOT_EXIST);
        }

        MemberProcessVO processVO = new MemberProcessVO();
        processVO.setId(ruleDO.getId());
        processVO.setRuleName(ruleDO.getRuleName());
        processVO.setRoleId(ruleDO.getSubRole().getId());
        processVO.setRoleName(ruleDO.getSubRole().getRoleName());
        processVO.setRoleTypeName(RoleTypeEnum.getName(ruleDO.getSubRole().getRoleType().getTypeEnum()));
        processVO.setMemberTypeName(MemberTypeEnum.getCodeMessage(ruleDO.getSubRole().getMemberType().getTypeEnum()));
        processVO.setBusinessTypeName(ruleDO.getSubRole().getBusinessType().getBusinessTypeName());
        processVO.setDepositoryProcessId(ruleDO.getBaseDepositoryProcessId());
        processVO.setChangedProcessId(ruleDO.getBaseDetailChangeProcessId());

        processVO.setDetails(ruleDO.getConfigs().stream().map(config -> {
            MemberConfigNameVO nameVO = new MemberConfigNameVO();
            nameVO.setId(config.getId());
            nameVO.setFieldLocalName(config.getFieldLocalName());
            nameVO.setGroupName(config.getGroupName());
            return nameVO;
        }).sorted(Comparator.comparingLong(MemberConfigNameVO::getId)).collect(Collectors.toList()));

        return Wrapper.success(processVO);
    }

    /**
     * 分页查询流程规则配置关联的入库资料
     *
     * @param headers Http头部信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<MemberConfigNameVO>> pageMemberProcessDepositDetails(HttpHeaders headers, MemberProcessDepositDetailPageVO pageVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);

        MemberProcessRuleDO ruleDO = memberProcessRuleRepository.findById(pageVO.getId()).orElse(null);
        if(ruleDO == null || !ruleDO.getMemberId().equals(loginUser.getMemberId()) || !ruleDO.getRoleId().equals(loginUser.getMemberRoleId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_PROCESS_RULE_NOT_EXIST);
        }

        List<MemberConfigDO> configList = StringUtils.hasLength(pageVO.getName()) ? ruleDO.getConfigs().stream().sorted(Comparator.comparingLong(MemberConfigDO::getId)).filter(memberConfigDO -> memberConfigDO.getFieldLocalName().contains(pageVO.getName().trim())).collect(Collectors.toList()) : ruleDO.getConfigs().stream().sorted(Comparator.comparingLong(MemberConfigDO::getId)).collect(Collectors.toList());

        long totalCount = configList.size();
        List<MemberConfigDO> pageList = CollectionPageUtil.pageList(configList, pageVO.getCurrent(), pageVO.getPageSize());
        return Wrapper.success(new PageData<>(totalCount, pageList.stream().map(config -> {
            MemberConfigNameVO nameVO = new MemberConfigNameVO();
            nameVO.setId(config.getId());
            nameVO.setFieldLocalName(config.getFieldLocalName());
            nameVO.setGroupName(config.getGroupName());
            return nameVO;
        }).collect(Collectors.toList())));
    }


    /**
     * 修改流程规则状态
     *
     * @param headers  Http头部信息
     * @param statusVO 接口参数
     * @return 修改结果
     */
    @Override
    public Wrapper<Void> updateMemberProcessRuleStatus(HttpHeaders headers, MemberProcessIdAndStatusVO statusVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);

        MemberProcessRuleDO ruleDO = memberProcessRuleRepository.findById(statusVO.getId()).orElse(null);
        if(ruleDO == null || !ruleDO.getMemberId().equals(loginUser.getMemberId()) || !ruleDO.getRoleId().equals(loginUser.getMemberRoleId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_PROCESS_RULE_NOT_EXIST);
        }

        ruleDO.setStatus(statusVO.getStatus());
        memberProcessRuleRepository.saveAndFlush(ruleDO);

        return Wrapper.success();
    }

    /**
     * 删除流程规则
     *
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 删除结果
     */
    @Override
    public Wrapper<Void> deleteMemberProcessRule(HttpHeaders headers, MemberProcessIdVO idVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromBusinessPlatform(headers);

        MemberProcessRuleDO ruleDO = memberProcessRuleRepository.findById(idVO.getId()).orElse(null);
        if(ruleDO == null || !ruleDO.getMemberId().equals(loginUser.getMemberId()) || !ruleDO.getRoleId().equals(loginUser.getMemberRoleId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_PROCESS_RULE_NOT_EXIST);
        }

        memberProcessRuleRepository.delete(ruleDO);

        return Wrapper.success();
    }

    /**
     * 查找流程ProcessKey，如上级会员没有配置，返回默认的流程规则
     *
     * @param relationDO      会员关系
     * @param processTypeEnum 流程类型枚举
     * @return 流程ProcessKey
     */
    @Override
    public ProcessBO findMemberProcessKey(MemberRelationDO relationDO, MemberProcessTypeEnum processTypeEnum) {
        return findMemberProcessKey(relationDO.getMemberId(), relationDO.getRoleId(), relationDO.getSubRole(), processTypeEnum);
    }

    /**
     * 查找流程ProcessKey
     *
     * @param memberId        上级会员Id
     * @param roleId          下级会员Id
     * @param subRole         下级会员角色
     * @param processTypeEnum 流程类型枚举
     * @return 流程ProcessKey
     */
    @Override
    public ProcessBO findMemberProcessKey(Long memberId, Long roleId, RoleDO subRole, MemberProcessTypeEnum processTypeEnum) {
        String processKey = "";
        Boolean emptyProcess = true;
        switch (processTypeEnum) {
            case MEMBER_DEPOSITORY:
                MemberProcessRuleDO depositoryProcessRuleDO = memberProcessRuleRepository.findFirstByMemberIdAndRoleIdAndSubRoleAndStatus(memberId, roleId, subRole, EnableDisableStatus.ENABLE.getCode());
                if(depositoryProcessRuleDO != null && StringUtils.hasLength(depositoryProcessRuleDO.getBaseDepositoryProcessKey())) {
                    processKey = depositoryProcessRuleDO.getBaseDepositoryProcessKey();
                    emptyProcess = depositoryProcessRuleDO.getEmptyDepositoryProcess() == null ? false : depositoryProcessRuleDO.getEmptyDepositoryProcess();
                } else {
                    BaseMemberProcessDO baseMemberProcessDO = baseMemberProcessRepository.findFirstByProcessTypeAndIsDefault(processTypeEnum.getCode(), EnableDisableStatus.ENABLE.getCode());
                    if(baseMemberProcessDO != null) {
                        processKey = baseMemberProcessDO.getProcessKey();
                        emptyProcess = baseMemberProcessDO.getEmptyProcess();
                    }
                }
                break;
            case MEMBER_MODIFICATION:
                MemberProcessRuleDO detailChangeProcessRuleDO = memberProcessRuleRepository.findFirstByMemberIdAndRoleIdAndSubRoleAndStatus(memberId, roleId, subRole, EnableDisableStatus.ENABLE.getCode());
                if(detailChangeProcessRuleDO != null && StringUtils.hasLength(detailChangeProcessRuleDO.getBaseDetailChangeProcessKey())) {
                    processKey = detailChangeProcessRuleDO.getBaseDetailChangeProcessKey();
                    emptyProcess = detailChangeProcessRuleDO.getEmptyDetailChangeProcess() == null ? false : detailChangeProcessRuleDO.getEmptyDetailChangeProcess();
                } else {
                    BaseMemberProcessDO baseMemberProcessDO = baseMemberProcessRepository.findFirstByProcessTypeAndIsDefault(processTypeEnum.getCode(), EnableDisableStatus.ENABLE.getCode());
                    if(baseMemberProcessDO != null) {
                        processKey = baseMemberProcessDO.getProcessKey();
                        emptyProcess = baseMemberProcessDO.getEmptyProcess();
                    }
                }
                break;
            default:
                break;
        }

        return new ProcessBO(processKey, emptyProcess);
    }

    /**
     * 下级会员角色是否存在非空的入库资料配置
     *
     * @param memberId        上级会员Id
     * @param roleId          上级会员角色Id
     * @param subRoles        下级会员角色列表
     * @return 是/否
     */
    @Override
    public boolean existDepositoryConfig(Long memberId, Long roleId, List<RoleDO> subRoles) {
        return memberProcessRuleRepository.existsByMemberIdAndRoleIdAndSubRoleInAndBaseDepositoryProcessIdGreaterThanAndConfigsIsNotNull(memberId, roleId, subRoles, 0L);
    }
}
